﻿using System;
using System.Data;
using System.Configuration;
using System.Linq;
using System.Xml.Linq;
using System.Collections;
using System.Collections.Generic;
using System.Web;
using System.Security.Cryptography;
using System.Text;
using System.Net;
using System.IO;

/// <summary>
/// Summary description for SohaPayment
/// </summary>

public class SohaPayment
{
    // URL for publish website
    public string PG_ROOT_URL = "";

    // This merchant code provided by SohaPay
    string Merchant_site_code = "";

    // This Secure secret provided by SohaPay
    string Secure_secret = "";

    /// <summary>
    /// URL Checkout payment
    /// </summary>
    string PG_url = "payment.php";

    /// <summary>
    /// URL query payment
    /// </summary>
    string PG_url_query = "payment_query.php";

    /// <summary>
    /// URL embed payment
    /// </summary>
    string PG_url_embed = "merchant_popup.php";

    public SohaPayment()
    {
        LoadConfig();

        PG_url = PG_ROOT_URL + PG_url;
        PG_url_query = PG_ROOT_URL + PG_url_query;
        PG_url_embed = PG_ROOT_URL + PG_url_embed;
    }

    void LoadConfig()
    {
        if (ConfigurationManager.AppSettings["env"] == "test")
        {
            PG_ROOT_URL = ConfigurationManager.AppSettings["PG_ROOT_URL_Test"];
            Merchant_site_code = ConfigurationManager.AppSettings["Merchant_site_code_Test"];
            Secure_secret = ConfigurationManager.AppSettings["Secure_secret_Test"];
        }
        else
        {
            PG_ROOT_URL = ConfigurationManager.AppSettings["PG_ROOT_URL"];
            Merchant_site_code = ConfigurationManager.AppSettings["Merchant_site_code"];
           Secure_secret = ConfigurationManager.AppSettings["Secure_secret"];
        }
    }

    /// <summary>
    /// Method build url checkout payment
    /// </summary>
    /// <param name="returnUrl">Url called return from SohaPay</param>
    /// <param name="orderCode">Order Code</param>
    /// <param name="orderPrice">Price</param>
    /// <param name="orderEmail">Email</param>
    /// <param name="orderMobile">Mobile</param>
    /// <param name="orderDescription">Detail description about order</param>
    /// <returns></returns>
    public string BuildCheckoutUrl(string returnUrl, string orderTitle, string orderCode, long orderPrice, string orderEmail, string orderMobile, string orderDescription)
    {
        // Param value send to SohaPay
        Hashtable arrparam = new Hashtable();
        arrparam["site_code"] = Merchant_site_code;
        arrparam["return_url"] = returnUrl;
        arrparam["transaction_info"] = orderDescription;
        arrparam["order_code"] = orderCode;
        arrparam["price"] = orderPrice.ToString();
        arrparam["order_email"] = orderEmail;
        arrparam["order_mobile"] = orderMobile;
        arrparam["order_product_title"] = orderTitle;
        arrparam["version"] = "2";

        // Step 2 : check redirect url have exists '?'
        string redirectUrl = PG_url;
        if (redirectUrl.LastIndexOf("?") == -1)
        {
            redirectUrl += "?";
        }
        else if (redirectUrl.Substring(returnUrl.Length - 1, 1) != "?" && redirectUrl.LastIndexOf("&") == -1)
        {
            redirectUrl += "&";
        }

        // Step 3 : make url
        ArrayList keys = new ArrayList();
        keys.AddRange(arrparam.Keys);
        keys.Sort();

        List<string> param = new List<string>();
        string secure_code = "";
        foreach (string k in keys)
        {
            if (arrparam[k].ToString().Length == 0) continue;

            param.Add(HttpContext.Current.Server.UrlEncode(k) + "=" + HttpContext.Current.Server.UrlEncode(arrparam[k].ToString()));
            secure_code += k + "=" + arrparam[k].ToString() + "&";
        }
        redirectUrl += string.Join("&", param.ToArray());

        secure_code = secure_code.TrimEnd('&');
        if (secure_code.Length > 0)
        {
            var hmacsha256 = new HMACSHA256(Encoding.UTF8.GetBytes(Secure_secret));


            redirectUrl += "&secure_hash=" + CreateSHA256Signature(Secure_secret, secure_code).ToUpper();

        }
        return redirectUrl;
    }

    /// <summary>
    /// Build Embed Url
    /// </summary>
    /// <param name="hashtable"></param>
    /// <returns></returns>
    public string BuildEmbedUrl(Hashtable hashtable) 
    { 
        string url = "";
        if (HttpContext.Current.Request.ServerVariables["SERVER_PORT"] == "80")
            url = "http://" + HttpContext.Current.Request.ServerVariables["SERVER_NAME"];
        else
            url = "http://" + HttpContext.Current.Request.ServerVariables["SERVER_NAME"] + ":" + HttpContext.Current.Request.ServerVariables["SERVER_PORT"];
        if (HttpContext.Current.Request.ApplicationPath != "/")
            url += HttpContext.Current.Request.ApplicationPath;

        Hashtable arrparam = new Hashtable();
        arrparam["site_code"]           = Merchant_site_code;
        arrparam["return_url"]          = checkExists(hashtable["return_url"]) != "" ? hashtable["return_url"].ToString() : url;
        arrparam["transaction_info"]    = checkExists(hashtable["transaction_info"]) != "" ? hashtable["transaction_info"].ToString() : "";
        arrparam["order_code"]          = checkExists(hashtable["order_code"]) != "" ? hashtable["order_code"].ToString() : this.DateTimeToUnixTimestamp(DateTime.Now).ToString() + '-' + this.RandomNumber(10000, 99999).ToString();
        arrparam["price"]               = checkExists(hashtable["price"]) != "" ? Int32.Parse(hashtable["price"].ToString()) : 0;
        arrparam["order_email"]         = checkExists(hashtable["order_email"]) != "" ? hashtable["order_email"].ToString() : "";
        arrparam["order_mobile"]        = checkExists(hashtable["order_mobile"]) != "" ? hashtable["order_mobile"].ToString() : "";
        arrparam["order_product_title"] = checkExists(hashtable["order_product_title"]) != "" ? hashtable["order_product_title"].ToString() : "Giao dịch thanh toán tiền";
        arrparam["order_product_id"]    = checkExists(hashtable["order_product_id"]) != "" ? Int32.Parse(hashtable["order_product_id"].ToString()) : 0;
        arrparam["order_product_unit"]  = checkExists(hashtable["order_product_unit"]) != "" ? hashtable["order_product_unit"].ToString() : "sản phẩm";
        arrparam["order_number_total"]  = checkExists(hashtable["order_number_total"]) != "" ? Int32.Parse(hashtable["order_number_total"].ToString()) : 10;
        arrparam["order_number_max"]    = checkExists(hashtable["order_number_max"]) != "" ? Int32.Parse(hashtable["order_number_max"].ToString()) : 10;
        arrparam["order_number_min"]    = checkExists(hashtable["order_number_min"]) != "" ? Int32.Parse(hashtable["order_number_min"].ToString()) : 1;
        arrparam["order_ship"]          = checkExists(hashtable["order_ship"]) != "" ? Int32.Parse(hashtable["order_ship"].ToString()) : 0;
        arrparam["order_ship_fee"]      = checkExists(hashtable["order_ship_fee"]) != "" ? Int32.Parse(hashtable["order_ship_fee"].ToString()) : 0;
        arrparam["order_ship_type"]     = checkExists(hashtable["order_ship_type"]) != "" ? Int32.Parse(hashtable["order_ship_type"].ToString()) : 3;
        arrparam["order_cod_fee"]       = checkExists(hashtable["order_cod_fee"]) != "" ? Int32.Parse(hashtable["order_cod_fee"].ToString()) : 0;
        arrparam["order_cod_type"]      = checkExists(hashtable["order_cod_type"]) != "" ? Int32.Parse(hashtable["order_cod_type"].ToString()) : 1;
        arrparam["payment_type"]        = checkExists(hashtable["payment_type"]) != "" ? hashtable["payment_type"].ToString() : "|1|";
        arrparam["embed_type"]          = checkExists(hashtable["embed_type"]) != "" ? hashtable["embed_type"].ToString() : "popup";
        arrparam["version"]             = "2";

        // Step 2 : check redirect url have exists '?'
        string redirectUrl = PG_url_embed;
        if (redirectUrl.LastIndexOf("?") == -1)
        {
            redirectUrl += "?";
        }
        else if (redirectUrl.Substring(redirectUrl.Length - 1, 1) != "?" && redirectUrl.LastIndexOf("&") == -1)
        {
            redirectUrl += "&";
        }

        // Step 3 : make url
        ArrayList keys = new ArrayList();
        keys.AddRange(arrparam.Keys);
        keys.Sort();

        List<string> param = new List<string>();
        string secure_code = "";
        foreach (string k in keys)
        {
            if (arrparam[k].ToString().Length == 0) continue;

            param.Add(HttpContext.Current.Server.UrlEncode(k) + "=" + HttpContext.Current.Server.UrlEncode(arrparam[k].ToString()));
            secure_code += k + "=" + arrparam[k].ToString() + "&";
        }
        redirectUrl += string.Join("&", param.ToArray());

        secure_code = secure_code.TrimEnd('&');
        if (secure_code.Length > 0)
        {
            var hmacsha256 = new HMACSHA256(Encoding.UTF8.GetBytes(Secure_secret));


            redirectUrl += "&secure_hash=" + CreateSHA256Signature(Secure_secret, secure_code).ToUpper();

        }
        return redirectUrl;
    }
   
    /// <summary>
    /// Method DoChargeCard
    /// </summary>
    /// <param name="card_code">Card Code</param>
    /// <param name="card_type">Card Type</param>
    /// <param name="transaction_info">Transaction Info</param>
    /// <param name="order_code">Order Code</param>
    /// <param name="order_email">Order Email</param>
    /// <param name="order_mobile">Order Mobile</param>
    /// <param name="card_seri">Card Seri</param>
    /// <returns>Hashtable</returns>

    public Hashtable DoChargeCard(string card_code, string card_type, string transaction_info, string order_code, string order_email, string order_mobile, string card_seri)
    {
		// Param value send to SohaPay
        Hashtable arrparam = new Hashtable();
        arrparam["site_code"] = Merchant_site_code;
        arrparam["card_code"] = card_code;
        arrparam["card_seri"] = card_seri;
        arrparam["card_type"] = card_type;
        arrparam["transaction_info"] = transaction_info;
        arrparam["order_code"] = order_code;
        arrparam["order_email"] = order_email;
        arrparam["order_mobile"] = order_mobile;
		arrparam["command"]		=	"doChargeMobileCard";
        arrparam["version"] = "2";

        // Step 2 : check redirect url have exists '?'
		string queryURL = PG_url_query;
		
		if (queryURL.LastIndexOf("?") == -1)
        {
            queryURL += "?";
        }
        else if (queryURL.Substring(queryURL.Length - 1, 1) != "?" && queryURL.LastIndexOf("&") == -1)
        {
            queryURL += "&";
        }
        
        // Step 3 : make url
        ArrayList keys = new ArrayList();
        keys.AddRange(arrparam.Keys);
        keys.Sort();
        
        List<string> param = new List<string>();
        string secure_code = "";
        foreach (string k in keys)
        {
            if (arrparam[k].ToString().Length == 0) continue;

            param.Add(HttpContext.Current.Server.UrlEncode(k) + "=" + HttpContext.Current.Server.UrlEncode(arrparam[k].ToString()));
            secure_code += k + "=" + arrparam[k].ToString() + "&";
        }

        queryURL += string.Join("&", param.ToArray());
        secure_code = secure_code.TrimEnd('&');
        if (secure_code.Length > 0)
        {
            var hmacsha256 = new HMACSHA256(Encoding.UTF8.GetBytes(Secure_secret));
            queryURL += "&secure_hash=" + CreateSHA256Signature(Secure_secret, secure_code).ToUpper();
        }
        
        System.Net.HttpWebRequest httpWebRequest = (System.Net.HttpWebRequest)WebRequest.Create(queryURL);
        httpWebRequest.Method = "POST";
        
        string response = null; 
        try 
        { 
            using (Stream s = httpWebRequest.GetRequestStream()) 
            {                 
                using (StreamWriter stw = new StreamWriter(s)) 
                {                         
                    stw.Write(s); //obviously this adds just the json object 
                                     //and not the array() map, hence the server 
                                     //returns an error.                                    
                } 
            }

            using (HttpWebResponse resp = httpWebRequest.GetResponse() as HttpWebResponse) 
            {
				var reader = new StreamReader(resp.GetResponseStream(), Encoding.UTF8); 
				response = reader.ReadToEnd(); 
            } 
        }
        catch(Exception ex) {
            Console.WriteLine(ex.Message);
        }

        Hashtable map = new Hashtable();
		
		if (response.Length == 0 || response.IndexOf("Exception") != -1)
        {
            map["shp_order_code"] = "order_code";
            map["shp_order_price"] = "";
            map["shp_payment_total"] = "";
            map["shp_payment_time"] = "";
            map["shp_order_info"] = "";
            map["shp_order_status"] = "0";
            map["shp_payment_response_description"] = "Card number is not valid";
        } 
		else {
			response = response.Substring(1, response.Length-1).ToString();

			string[] pairArray = response.Split('&');
			foreach(string pair in pairArray)
			{
				string[] paramSplit = pair.Split('=');
				map[HttpUtility.UrlDecode(paramSplit[0])] = HttpUtility.UrlDecode(paramSplit[1]);
			}

			string response_code = "";
			if (map["response_code"] != null) {
				response_code = map["response_code"].ToString();
			}

			map["shp_payment_response_description"] = this.getResponseDescriptionMobileCard(response_code);
		}
        return map;
    }

    /// <summary>
    /// Method QueryOrderStatus
    /// </summary>
    /// <param name="order_code">Order Code</param>
    /// <param name="command">
    /// Command: 
    /// + query: Payment Master Card or Local Card
    /// + queryMobileCard: Payment card 
    /// </param>
    /// <returns>Hashtable</returns>
    public Hashtable QueryOrderStatus(string order_code, string command) 
    {
        Hashtable arrparam = new Hashtable();
        arrparam["site_code"] = Merchant_site_code;
        arrparam["order_code"] = order_code;
        arrparam["command"] = command;
        arrparam["version"] = "2";

        // Step 2 : check redirect url have exists '?'
        string queryURL = PG_url_query;

        if (queryURL.LastIndexOf("?") == -1)
        {
            queryURL += "?";
        }
        else if (queryURL.Substring(queryURL.Length - 1, 1) != "?" && queryURL.LastIndexOf("&") == -1)
        {
            queryURL += "&";
        }

        // Step 3 : make url
        ArrayList keys = new ArrayList();
        keys.AddRange(arrparam.Keys);
        keys.Sort();

        List<string> param = new List<string>();
        string secure_code = "";
        foreach (string k in keys)
        {
            if (arrparam[k].ToString().Length == 0) continue;

            param.Add(HttpContext.Current.Server.UrlEncode(k) + "=" + HttpContext.Current.Server.UrlEncode(arrparam[k].ToString()));
            secure_code += k + "=" + arrparam[k].ToString() + "&";
        }

        queryURL += string.Join("&", param.ToArray());
        secure_code = secure_code.TrimEnd('&');
        if (secure_code.Length > 0)
        {
            var hmacsha256 = new HMACSHA256(Encoding.UTF8.GetBytes(Secure_secret));
            queryURL += "&secure_hash=" + CreateSHA256Signature(Secure_secret, secure_code).ToUpper();
        }

        System.Net.HttpWebRequest httpWebRequest = (System.Net.HttpWebRequest)WebRequest.Create(queryURL);
        httpWebRequest.Method = "POST";

        string response = null;
        try
        {
            using (Stream s = httpWebRequest.GetRequestStream())
            {
                using (StreamWriter stw = new StreamWriter(s))
                {
                    stw.Write(s); //obviously this adds just the json object 
                    //and not the array() map, hence the server 
                    //returns an error.                                    
                }
            }

            using (HttpWebResponse resp = httpWebRequest.GetResponse() as HttpWebResponse)
            {
                var reader = new StreamReader(resp.GetResponseStream(), Encoding.UTF8);
                response = reader.ReadToEnd();
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }

        Hashtable map = new Hashtable();
  
        string[] pairArray = response.Split('&');
        foreach (string pair in pairArray)
        {
            string[] paramSplit = pair.Split('=');
            map[HttpUtility.UrlDecode(paramSplit[0])] = HttpUtility.UrlDecode(paramSplit[1]);
        }

        map["shp_payment_response_description"] = "";
        if (map["shp_payment_type"].ToString() != "" && Convert.ToInt32(map["shp_payment_type"].ToString()) == 1)
        { 
            map["shp_payment_response_description"] = this.GetResponseDescriptionInternational(map["shp_payment_response_code"].ToString());
        }
        else if (map["shp_payment_type"].ToString() != "" && Convert.ToInt32(map["shp_payment_type"].ToString()) == 2)
        {
            map["shp_payment_response_description"] = this.GetResponseDescriptionDomestic(map["shp_payment_response_code"].ToString());
        }
        else if (map["shp_payment_type"].ToString() != "" && Convert.ToInt32(map["shp_payment_type"].ToString()) == 3) 
        {
            map["shp_payment_response_description"] = this.getResponseDescriptionMobileCard(map["shp_payment_response_code"].ToString());
        }
        return map;
    }

    /// <summary>
    /// Method VerifyReturnUrl
    /// </summary>
    /// <returns>bool</returns>

    public bool VerifyReturnUrl()
    {
        string secure_hash = HttpContext.Current.Request["secure_code"];
        Hashtable param = new Hashtable();
        param["order_product_title"] = !string.IsNullOrEmpty(HttpContext.Current.Request["order_product_title"]) ? HttpContext.Current.Request["order_product_title"] : "";
        param["transaction_info"] = !string.IsNullOrEmpty(HttpContext.Current.Request["transaction_info"]) ? HttpContext.Current.Request["transaction_info"] : "";
        param["order_code"] = !string.IsNullOrEmpty(HttpContext.Current.Request["order_code"]) ? HttpContext.Current.Request["order_code"] : "";
        param["order_email"] = !string.IsNullOrEmpty(HttpContext.Current.Request["order_email"]) ? HttpContext.Current.Request["order_email"] : "";
        param["order_session"] = !string.IsNullOrEmpty(HttpContext.Current.Request["order_session"]) ? HttpContext.Current.Request["order_session"] : "";
        param["price"] = !string.IsNullOrEmpty(HttpContext.Current.Request["price"]) ? HttpContext.Current.Request["price"] : "";
        param["site_code"] = !string.IsNullOrEmpty(HttpContext.Current.Request["site_code"]) ? HttpContext.Current.Request["site_code"] : "";
        param["response_code"] = !string.IsNullOrEmpty(HttpContext.Current.Request["response_code"]) ? HttpContext.Current.Request["response_code"] : "";
        param["response_message"] = !string.IsNullOrEmpty(HttpContext.Current.Request["response_message"]) ? HttpContext.Current.Request["response_message"] : "";
        param["payment_type"] = !string.IsNullOrEmpty(HttpContext.Current.Request["payment_type"]) ? HttpContext.Current.Request["payment_type"] : "";
        param["payment_time"] = !string.IsNullOrEmpty(HttpContext.Current.Request["payment_time"]) ? HttpContext.Current.Request["payment_time"] : "";
        param["error_text"] = !string.IsNullOrEmpty(HttpContext.Current.Request["error_text"]) ? HttpContext.Current.Request["error_text"] : "";

        ArrayList keys = new ArrayList();
        keys.AddRange(param.Keys);
        keys.Sort();

        string secure_code = "";
        foreach (string k in keys)
        {
            if (k != "secure_code" && param[k].ToString().Length > 0)
            {
                secure_code += k + "=" + param[k].ToString() + "&";
            }
        }

        secure_code = secure_code.TrimEnd('&');

        if (secure_hash.ToUpper() == CreateSHA256Signature(Secure_secret, secure_code))
        {
            return true;
        }

        return false;
    }

    /// <summary>
    /// Method GetResponseDescriptionInternational
    /// </summary>
    /// <param name="responseCode">Response Code</param>
    /// <returns>String</returns>
    public string GetResponseDescriptionInternational(string responseCode)
    {
        string result = "";
        switch (responseCode)
        {
            case "0": result = "Successful transactions"; break;
            case "?": result = "Transaction status unknown"; break;
            case "1": result = "Unknown error"; break;
            case "2": result = "Bank transactions is refuse"; break;
            case "3": result = "No response from Bank"; break;
            case "4": result = "Card expires"; break;
            case "5": result = "The balance is not enough to pay"; break;
            case "6": result = "Error communicating with the Bank"; break;
            case "7": result = "Error Payment System server"; break;
            case "8": result = "Transaction type is not supported"; break;
            case "9": result = "Bank transactions declined (no relation to the Bank)"; break;
            case "A": result = "Transaction Aborted"; break;
            case "B": result = "Blocked due to fraud risk"; break;
            case "C": result = "transaction is canceled"; break;
            case "D": result = "transaction has been deferred pending receipt"; break;
            case "E": result = "Referred"; break;
            case "F": result = "3D Secure authentication failed"; break;
            case "I": result = "Card Security Code verification fails"; break;
            case "L": result = "Procurement transaction is closed (Please try again in a transaction)"; break;
            case "N": result = "Cardholder not enrolled in the program authentication"; break;
            case "P": result = "transactions have been received by the Payment Adaptor and is being processed"; break;
            case "R": result = "transaction was not handled - has reached the limit of retry attempts allowed"; break;
            case "S": result = "SessionID duplicate (OrderInfo)"; break;
            case "T": result = "Address verification is not correct"; break;
            case "U": result = "Card Security Code is not correct"; break;
            case "V": result = "Address Verification and Card Security Code is incorrect"; break;
            case "9999": result = "Transaction fraud risk"; break;
            case "9998": result = "Transaction fraud risk, to authenticate the cardholder"; break;
            case "PG": result = "Transaction does not exist on the system"; break;
            default: result = "Unable to determine"; break;
        }
        return result;
    }

    /// <summary>
    /// Method GetResponseDescriptionDomestic
    /// </summary>
    /// <param name="responseCode">Response Code</param>
    /// <returns>String</returns>
    public string GetResponseDescriptionDomestic(string responseCode)
    {
        string result = "";
        switch (responseCode)
        {
            case "0": result = "Successful transactions"; break;
            case "1": result = "Bank rejected transactions"; break;
            case "3": result = "Unit code does not exist"; break;
            case "4": result = "Incorrect Access Code"; break;
            case "5": result = "The amount is invalid"; break;
            case "6": result = "Currency code does not exist"; break;
            case "7": result = "Unknown error"; break;
            case "8": result = "Incorrect card number"; break;
            case "9": result = "Incorrect cardholder name"; break;
            case "10": result = "Card expiration / card locked"; break;
            case "11": result = "Unregistered card using the online payment service."; break;
            case "12": result = "Release date / expired variance"; break;
            case "13": result = "Exceed the payment limits"; break;
            case "21": result = "The balance is not enough to pay"; break;
            case "99": result = "The user canceled the transaction"; break;
            case "100": result = "Do not enter card information / Cancel payment transaction"; break;
            case "PG": result = "Transaction does not exist on the system"; break;
            default: result = "Unable to determine"; break;
        }
        return result;
    }

    /// <summary>
    /// Method getResponseDescriptionMobileCard
    /// </summary>
    /// <param name="responseCode">Response Code</param>
    /// <returns>String</returns>
    public string getResponseDescriptionMobileCard(string responseCode)
    {
        string result = "";
        switch (responseCode)
        {
            case "1": result = "Successful transactions"; break;
            case "-1": result = "Card used"; break;
            case "-2": result = "Card blocked"; break;
            case "-3": result = "Card has expired"; break;
            case "-4": result = "Card not activated"; break;
            case "-10": result = "Card number is not valid"; break;
            case "-11": result = "Card number is not valid"; break;
            case "-12": result = "Card does not exist"; break;
            case "-99": result = "System Error"; break;
            case "0": result = "Other Error"; break;
            case "2": result = "No login functions using charge"; break;
            case "3": result = "Error VDCO system"; break;
            case "4": result = "Card can not be used (common error Vinaphone)"; break;
            case "5": result = "Make the wrong 5 times in a row"; break;
            case "6": result = "Performs the logout fails"; break;
            case "8": result = "Charge card faulty system. This error needs for control and control"; break;
            case "9": result = "Partner information is incorrect"; break;
            case "10": result = "False information email or mobile format"; break;
            default: result = "Unable to determine"; break;
        }
        return result;
    }

    /// <summary>
    /// Method Sort
    /// </summary>
    /// <param name="table">table</param>
    /// <returns>Hashtable</returns>
    Hashtable Sort(Hashtable table)
    {
        ArrayList keys = new ArrayList();
        keys.AddRange(table.Keys);
        keys.Sort();

        Hashtable tmp = new Hashtable();
        foreach (string k in keys)
        {
            tmp[k] = table[k];
        }
        return tmp;
    }

    /// <summary>
    /// Method CreateSHA256Signature
    /// </summary>
    /// <param name="key">key</param>
    /// <param name="data">data</param>
    /// <returns>String</returns>
    string CreateSHA256Signature(string key, string data)
    {
        /*
        byte[] convertedHash = new byte[key.Length / 2];
        for (int i = 0; i < key.Length / 2; i++)
        {
            convertedHash[i] = Convert.ToByte(int.Parse(key.Substring(i * 2, 2), System.Globalization.NumberStyles.HexNumber));
        }
        */
        if ((key.Length % 2) == 1) key += '0';
        byte[] bytes = new byte[key.Length / 2];
        for (int i = 0; i < key.Length; i += 2)
        {
            bytes[i / 2] = Convert.ToByte(key.Substring(i, 2), 16);
        }

        var hmacsha256 = new HMACSHA256(bytes);
        byte[] hashValue = hmacsha256.ComputeHash(Encoding.UTF8.GetBytes(data));
        string hexHash = "";
        foreach (byte test in hashValue)
        {
            hexHash += test.ToString("X2");
        }
        return hexHash;
    }
    
    /// <summary>
    /// Create ramdom code
    /// </summary>
    /// <param name="min"></param>
    /// <param name="max"></param>
    /// <returns></returns>
    private int RandomNumber(int min, int max)
    {
        Random random = new Random();
        return random.Next(min, max);
    }

    /// <summary>
    /// Create Timestamp
    /// </summary>
    /// <param name="_DateTime"></param>
    /// <returns></returns>
    public long DateTimeToUnixTimestamp(DateTime _DateTime)
    {
        TimeSpan _UnixTimeSpan = (_DateTime - new DateTime(1970, 1, 1, 0, 0, 0));
        return (long)_UnixTimeSpan.TotalSeconds;
    }

    /// <summary>
    /// Check Exists Object
    /// </summary>
    /// <param name="strParam">Object strParam</param>
    /// <returns>string</returns>
    protected string checkExists(Object strParam)
    {
        string str = "";
        if (strParam != null)
        {
            str = strParam.ToString();
        }
        else
        {
            str = "";
        }

        return str;
    }
}
